package com.gitee.wsl.mathematics.matrix.mat4

import com.gitee.wsl.mathematics.matrix.M
import com.gitee.wsl.mathematics.matrix.MatCopyInitializer
import com.gitee.wsl.mathematics.matrix.MatrixD
import com.gitee.wsl.mathematics.matrix.MatrixF
import com.gitee.wsl.mathematics.matrix.MutableMatrix
import com.gitee.wsl.mathematics.matrix.N
import com.gitee.wsl.mathematics.matrix.mat2.MutableMatrix2
import com.gitee.wsl.mathematics.matrix.mat4.ext.mul33
import com.gitee.wsl.mathematics.vector.vec4.MutableVector4
import com.gitee.wsl.mathematics.vector.vec4.Vector4

interface MutableMatrix4<T:Number,V: Matrix4<T, V, R>,R: Vector4<T, R>>: Matrix4<T, V, R>,MutableMatrix<T,V,R>{

    override var m00: T get() = proxy[0]  ;set(value) { proxy[0] = value }
    override var m01: T get() = proxy[1]  ;set(value) { proxy[1] = value }
    override var m02: T get() = proxy[2]  ;set(value) { proxy[2] = value }
    override var m03: T get() = proxy[3]  ;set(value) { proxy[3] = value }
    override var m10: T get() = proxy[4]  ;set(value) { proxy[4] = value }
    override var m11: T get() = proxy[5]  ;set(value) { proxy[5] = value }
    override var m12: T get() = proxy[6]  ;set(value) { proxy[6] = value }
    override var m13: T get() = proxy[7]  ;set(value) { proxy[7] = value }
    override var m20: T get() = proxy[8]  ;set(value) { proxy[8] = value }
    override var m21: T get() = proxy[9]  ;set(value) { proxy[9] = value }
    override var m22: T get() = proxy[10] ;set(value) { proxy[10] = value }
    override var m23: T get() = proxy[11] ;set(value) { proxy[11] = value }
    override var m30: T get() = proxy[12] ;set(value) { proxy[12] = value }
    override var m31: T get() = proxy[13] ;set(value) { proxy[13] = value }
    override var m32: T get() = proxy[14] ;set(value) { proxy[14] = value }
    override var m33: T get() = proxy[15] ;set(value) { proxy[15] = value }

    override val m: List<MutableVector4<T, R>>

    override val n: List<MutableVector4<T, R>>

    override fun createVec4(block:(MutableVector4<T, *>)->Unit): MutableVector4<T, *>

    override fun createMat2(block:(MutableMatrix2<T, *, *>)->Unit): MutableMatrix2<T, *, *>

    override fun createVec(indexes: List<Int>): MutableVector4<T,R>

    override fun toMutable() = this

    override operator fun M.get(row: Int) = createVec(rowIndexes(row))

    override operator fun N.get(col: Int) = createVec(colIndexes(col))

    override fun copy(block: MatCopyInitializer<T>): MutableMatrix4<T, V, R>

    override fun copyEmpty() = copy(block ={ _, _ -> zero})

    override fun copyIdentity() = copy(block ={ i, j -> if( i == j) one else zero})

    override fun scale(factor: T) = mul33(
        factor, zero, zero,
        zero, factor, zero,
        zero, zero, factor
    )

    fun set(
        m00: T, m01: T, m02: T, m03: T,
        m10: T, m11: T, m12: T, m13: T,
        m20: T, m21: T, m22: T, m23: T,
        m30: T, m31: T, m32: T, m33: T
    ){
        m[0].set(m00, m01, m02, m03)
        m[1].set(m10, m11, m12, m13)
        m[2].set(m20, m21, m22, m23)
        m[3].set(m30, m31, m32, m33)
    }


    fun copyFrom(other: Matrix4<T, *,*>) {
        for (i in 0..15) {
            proxy[i] = other.proxy[i]
        }
    }

    operator fun set(row: Int,m: Vector4<T, *>) = M.set(row,m)

    operator fun M.set(row: Int, m: Vector4<T, *>){
        set(row,0,m[0])
        set(row,1,m[1])
        set(row,2,m[2])
        set(row,3,m[3])
    }

    operator fun N.set(colIndex: Int, m: Vector4<T, *>){
        set(0,colIndex,m[0])
        set(1,colIndex,m[1])
        set(2,colIndex,m[2])
        set(3,colIndex,m[3])
    }

    override fun copy(
        m00: T?, m01: T?, m02: T?, m03: T?,
        m10: T?, m11: T?, m12: T?, m13: T?,
        m20: T?, m21: T?, m22: T?, m23: T?,
        m30: T?, m31: T?, m32: T?, m33: T?
    )  = create(
        m00 ?: this.m00,
        m01 ?: this.m01,
        m02 ?: this.m02,
        m03 ?: this.m03,
        m10 ?: this.m10,
        m11 ?: this.m11,
        m12 ?: this.m12,
        m13 ?: this.m13,
        m20 ?: this.m20,
        m21 ?: this.m21,
        m22 ?: this.m22,
        m23 ?: this.m23,
        m30 ?: this.m30,
        m31 ?: this.m31,
        m32 ?: this.m32,
        m33 ?: this.m33
    )

    /*
    override fun timesAssign(other: V) = set(
        m00 * other.m00 + m01 * other.m10 + m02 * other.m20 + m03 * other.m30,
        m00 * other.m01 + m01 * other.m11 + m02 * other.m21 + m03 * other.m31,
        m00 * other.m02 + m01 * other.m12 + m02 * other.m22 + m03 * other.m32,
        m00 * other.m03 + m01 * other.m13 + m02 * other.m23 + m03 * other.m33,

        m10 * other.m00 + m11 * other.m10 + m12 * other.m20 + m13 * other.m30,
        m10 * other.m01 + m11 * other.m11 + m12 * other.m21 + m13 * other.m31,
        m10 * other.m02 + m11 * other.m12 + m12 * other.m22 + m13 * other.m32,
        m10 * other.m03 + m11 * other.m13 + m12 * other.m23 + m13 * other.m33,

        m20 * other.m00 + m21 * other.m10 + m22 * other.m20 + m23 * other.m30,
        m20 * other.m01 + m21 * other.m11 + m22 * other.m21 + m23 * other.m31,
        m20 * other.m02 + m21 * other.m12 + m22 * other.m22 + m23 * other.m32,
        m20 * other.m03 + m21 * other.m13 + m22 * other.m23 + m23 * other.m33,

        m30 * other.m00 + m31 * other.m10 + m32 * other.m20 + m33 * other.m30,
        m30 * other.m01 + m31 * other.m11 + m32 * other.m21 + m33 * other.m31,
        m30 * other.m02 + m31 * other.m12 + m32 * other.m22 + m33 * other.m32,
        m30 * other.m03 + m31 * other.m13 + m32 * other.m23 + m33 * other.m33
    )
*/
}

interface MutableMatrix4F<V: Matrix4<Float, V,  R>,R:Vector4<Float,R>>:  MutableMatrix4<Float, V, R>, MatrixF<V, R>

interface MutableMatrix4D<V: Matrix4<Double, V, R>,R:Vector4<Double,R>>: MutableMatrix4<Double, V, R>, MatrixD<V, R>